package oop.ex2.main;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.regex.*;

import oop.ex2.method.Method;
import oop.ex2.method.inBlock;
import oop.ex2.variables.BadVaraiableException;
import oop.ex2.variables.Variables;




public class Main {
	private static HashMap<String,Method> methods=new HashMap<String, Method>();
	private static HashMap<String,Variables> variables=new HashMap<String, Variables>();
	public final static String VAR_REGEX="(final\\s)?\\s*(int|double|String|boolean|char)\\s+([\\S+^=^;])\\s*";
	public final static String VAR_END="(=\\s*(\\S+)\\s*;|;)";
	private final static String SCOMMENT="(//)|(/\\*|/\\*\\*)";
//	private final static String ECOMMENT="\\*/";
	/**
	 * reads the command file and saves each line in an arraylist.
	 * each line that have been red is sorted
	 * @param source the file to read
	 * @throws IOException 
	 * @throws BadVaraiableException 
	 */
	public static void fileReader(File source) throws IOException, BadVaraiableException{
		ArrayList <String> fileLines;	
		fileLines =new ArrayList<String>();
		//creates a new BufferedReader for the source file
		BufferedReader reader=new BufferedReader(new FileReader(source));
		String line;
		Matcher match=null;
		chekcer[] enums=chekcer.values();
		//reads the file line by line
		while((line=reader.readLine())!=null){
			//ignore empty lines
			while(line!=null && line.matches("\\s+"))
				line=reader.readLine();
			line = removeComments(reader, line);
			//classifies lines
			for(chekcer e:enums){
				match=e.getPatt().matcher(line);
				if (match.matches()){
					addBlock(e,match, reader);
					break;
				}
			}
		}	
		fileLines.trimToSize();
	}

	/**
	 * @param reader
	 * @param line
	 * @return
	 * @throws IOException
	 */
	private static String removeComments(BufferedReader reader, String line)
			throws IOException {
		Matcher match;
		String oneLine=("/\\*.*\\*/|/\\**.*\\*/");
		String multiLine=("/\\*.*|\\*/|/\\**.*");
		//removes comments
		match=Pattern.compile(SCOMMENT).matcher(line);
		if(match.find()){
			while(line!=null){
				if(line.startsWith("//"))
					line=reader.readLine();
				line=line.replaceAll(oneLine, " ");
				if(line.matches(multiLine)){
					while(line!=null&&!line.contains("*/")){
						line=reader.readLine();
					}
					line=line.replaceAll(".*\\*/", " ");
				}
				if(line.matches("[^\\S]"))
						line=reader.readLine();
				else
					return line;
			}
		}
		return line;
	}

	private static void addBlock(chekcer lineType,Matcher match, BufferedReader reader) throws BadVaraiableException, IOException {
		String line=null;
		switch(lineType){
			case METHOD:
				int i=1;
				ArrayList <String> methodLines=new ArrayList<String>();
				while((line=reader.readLine())!=null && i>0 ){
					if(line.contains("{"))
						i++;
					if(line.contains("}"))
						i--;
					if(i>0)
						methodLines.add(line);
				}
				System.out.println(match.groupCount());
				methods.put(match.group(2), new Method(match.group(2),match.group(1),match.group(3),methodLines));
				break;
			case VARIABLE:
				variables.put(match.group(3), new Variables(match.group(1),match.group(2),match.group(3),match.group(5)));
				break;
			}
	}
	
	/**
	 * 
	 * @param vars
	 * @param iter
	 * @return
	 * @throws badInitiationException 
	 * @throws BadVaraiableException 
	 */
	private void checkBlock(HashMap<String, Variables> vars, Iterator<String> iter) throws badInitiationException, BadVaraiableException{
		inBlock[] blocks=inBlock.values();
		String line=null;
		Matcher match=null;
		while(iter.hasNext()){
			line=iter.next();
			for(inBlock tempBlock:blocks){
				match=tempBlock.getPatt().matcher(line);
				if (match.matches()){
					HashMap<String, Variables> tempMap=new HashMap<String, Variables>(vars);
					switch (tempBlock) {
					case IF:
						checkBlock(tempMap, iter);
						break;
					case METHODCALL:
						checkMethodCall(line, vars);
						break;
					case VARIABLEDEC:
						vars.put(match.group(3), new Variables(match.group(1),match.group(2),match.group(3),match.group(4)));
						break;
					case VARIABLEINIT:
						checkVar(vars.get(match.group(1)), match.group(2), tempMap);
						break;
					case WHILE:
						checkBlock(tempMap, iter);
						break;

					default:
						break;
					}
				}
			}
		}
	}
	
//	private static boolean checkInitiation(Method method, Variables var){
//		if(method.getType().equals(var.getType()))
//			return true;
//		return false;
//	}
//	
//	private static boolean checkMethodCall(Method method,String call){
//		
//		if(inputIter.hasNext() || varsIter.hasNext())
//			return false;
//		return true;
//	}



	private static ArrayList<String> extractVars(String str) {
		char[] c=str.toCharArray();
		ArrayList<String> inputVars=new ArrayList<String>();
		int brackets=0;
		int start=0;
		for(int i=0; i<c.length;i++ ){
			if(c[i]=='(')
				brackets++;
			else if(c[i]==')')
				brackets--;
			if(brackets==0 && (c[i]==',' || c[i]==')')){
				inputVars.add(str.substring(start, i));
				start=i+1;
			}
		}
		return inputVars;
	}
	
	private static void checkVar(Variables var,String value, HashMap<String, Variables> tempVars) throws badInitiationException{
		if (var.getValue()!=null){
//			if(var.getType().getPatt().matcher(var.getValue()).matches())
//				return var.getType();
//			else 
			if(!var.getValue().matches("\\s*\\S+\\(\\s*(\\S+)\\s*\\);")){//check if initiate				
				if(tempVars==null || tempVars.containsKey(value))
//					return var.getType();
//				else
					throw new badInitiationException();
			}
			else{
				checkMethodCall(value, tempVars);
			}
		}
	}

	/**
	 * @param value
	 * @param tempVars
	 * @throws badInitiationException
	 */
	private static void checkMethodCall(String value,
			HashMap<String, Variables> tempVars) throws badInitiationException {
		Method tempMethod=methods.get(value.substring(0, value.indexOf('(')));
		ArrayList<String> inputVars=extractVars(value.substring(1, value.length()));
		ArrayList<Variables> methodVars=tempMethod.getInput();
		if(inputVars.size()!=methodVars.size())
			throw new badInitiationException();
		Iterator<String> inputIter=inputVars.iterator();
		Iterator<Variables> varsIter=methodVars.iterator();
		while(inputIter.hasNext() && varsIter.hasNext())
			checkVar(varsIter.next(), inputIter.next(),tempVars);
	}
	
	/**
	 * @param args
	 * @throws badInitiationException 
	 */
	public static void main(String[] args) throws badInitiationException {

		try {
			fileReader(new File(args[0]));	
			Collection<Variables> vars=variables.values();
			Iterator<Variables> varIter=vars.iterator();
			while(varIter.hasNext()){
				Variables tempVar=varIter.next();
				checkVar(tempVar,tempVar.getValue(),variables);
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BadVaraiableException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	

}
